约 6665 字

约 33 分钟

#C 语言标准库头文件 fenv.h

这个头文件提供 浮点数环境 的相关功能,例如浮点异常处理、舍入方向控制等。

#示例

#include <stdio.h>
#include <fenv.h>
#include <math.h>
#include <errno.h>

void show_exceptions(void) {
    printf("当前浮点异常状态: ");
    if (fetestexcept(FE_ALL_EXCEPT) == 0) {
        printf("无异常\n");
        return;
    }
    
    if (fetestexcept(FE_DIVBYZERO)) printf("除零异常 ");
    if (fetestexcept(FE_INVALID))   printf("无效操作异常 ");
    if (fetestexcept(FE_OVERFLOW))  printf("上溢异常 ");
    if (fetestexcept(FE_UNDERFLOW)) printf("下溢异常 ");
    if (fetestexcept(FE_INEXACT))   printf("不精确结果异常 ");
    printf("\n");
}

void show_rounding_mode(void) {
    printf("当前舍入模式: ");
    switch (fegetround()) {
        case FE_TONEAREST:  printf("四舍五入\n"); break;
        case FE_DOWNWARD:   printf("向负无穷方向舍入\n"); break;
        case FE_UPWARD:     printf("向正无穷方向舍入\n"); break;
        case FE_TOWARDZERO: printf("向零舍入\n"); break;
        default:            printf("未知模式\n");
    }
}

int main(void) {
    // 1. 显示初始浮点环境
    printf("=== 初始浮点环境 ===\n");
    show_exceptions();
    show_rounding_mode();
    printf("\n");
    
    // 2. 触发浮点异常示例
    printf("=== 触发浮点异常 ===\n");
    feclearexcept(FE_ALL_EXCEPT);  // 清除所有异常标志
    
    // 除零异常
    double x = 1.0, y = 0.0;
    double z = x / y;
    printf("1.0 / 0.0 = %f\n", z);
    show_exceptions();
    
    // 无效操作异常
    double a = sqrt(-1.0);
    printf("sqrt(-1.0) = %f\n", a);
    show_exceptions();
    printf("\n");
    
    // 3. 舍入模式控制示例
    printf("=== 舍入模式控制 ===\n");
    fesetround(FE_DOWNWARD);  // 设置为向负无穷舍入
    show_rounding_mode();
    
    double num = 1.75;
    printf("1.75 舍入后: %f\n", rint(num));
    
    fesetround(FE_UPWARD);    // 设置为向正无穷舍入
    show_rounding_mode();
    printf("1.75 舍入后: %f\n", rint(num));
    
    fesetround(FE_TONEAREST); // 恢复默认舍入模式
    printf("\n");
    
    // 4. 浮点环境保存与恢复
    printf("=== 环境保存与恢复 ===\n");
    fenv_t env;
    fegetenv(&env);  // 保存当前环境
    
    // 修改环境
    fesetround(FE_TOWARDZERO);
    feclearexcept(FE_ALL_EXCEPT);
    
    printf("修改后的环境:\n");
    show_rounding_mode();
    show_exceptions();
    
    fesetenv(&env);  // 恢复原始环境
    printf("\n恢复后的环境:\n");
    show_rounding_mode();
    show_exceptions();
    
    return 0;
}

运行结果:

user@host:~ $ gcc main.c -lm
user@host:~ $ ./a.out
=== 初始浮点环境 ===
当前浮点异常状态: 无异常
当前舍入模式: 四舍五入

=== 触发浮点异常 ===
1.0 / 0.0 = inf
当前浮点异常状态: 除零异常
sqrt(-1.0) = -nan
当前浮点异常状态: 除零异常 无效操作异常

=== 舍入模式控制 ===
当前舍入模式: 向负无穷方向舍入
1.75 舍入后: 1.000000
当前舍入模式: 向正无穷方向舍入
1.75 舍入后: 2.000000

=== 环境保存与恢复 ===
修改后的环境:
当前舍入模式: 向零舍入
当前浮点异常状态: 无异常

恢复后的环境:
当前舍入模式: 四舍五入
当前浮点异常状态: 除零异常 无效操作异常 不精确结果异常

#类型

类型标准说明
fenv_tC99表示整个浮点环境的类型
fexcept_tC99表示整个浮点异常标志的类型

#函数

函数标准说明
feclearexcepC99清除指定的浮点异常
fetestexceptC99检查指定的浮点异常
feraiseexceptC99产生指定的浮点异常
fegetexceptflagC99整体获取浮点异常标志
fesetexceptflagC99整体设置浮点异常标志
fegetroundC99获取舍入方向
fesetroundC99设置舍入方向
fegetenvC99获取浮点环境
fesetenvC99设置浮点环境
feholdexceptC99保存浮点环境并清空浮点异常
feupdateenvC99恢复浮点环境并触发浮点异常

#宏

宏标准说明
FE_DFL_ENVC99指向默认浮点环境的指针
浮点数异常宏标准说明
FE_ALL_EXCEPTC99所有支持的浮点异常的按位或
FE_DIVBYZEROC99浮点运算中发生了极点错误
FE_INEXACTC99结果不精确:需要进行舍入才能存储
FE_INVALIDC99浮点运算中发生了域错误
FE_OVERFLOWC99浮点运算的结果太大而溢出
FE_UNDERFLOWC99浮点运算的结果太小而损失精度
浮点数舍入方向宏 标准说明
FE_DOWNWARDC99向负无穷方向舍入
FE_TONEARESTC99四舍五入到最接近的可表示值
FE_TOWARDZEROC99向零舍入
FE_UPWARDC99向正无穷方向舍入

#推荐阅读

更新: 2026/1/19

作者: PlanC

创建: 2025/6/1